////////////////////////////////////////////////
// DESCRIPTION:
//     Class to encapsulate access to bus drivers
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

#include <FusionWare\Win32.h>
#include <string.hxx>
#include <CeBusCfg.h>

namespace FusionWare
{
    namespace DFX
    {
        ///////////////////////////////////////////////////////
        // Description: 
        //    Class to wrap up the use of bus driver handles
        //    and DeviceIoControl codes.
        //
        class BusDriver : protected FusionWare::Win32::File
		{
		public:
            BusDriver() {}
            BusDriver(const TCHAR* pBusName) { Open(pBusName); }
            virtual ~BusDriver() { Close(); }
            
            bool IsValid() const { return File::IsValid(); }

            bool Open(const TCHAR* pBusName)
            { 
                return File::Open(pBusName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE);
            }

            bool Close() { return File::Close(); }

            // MS has not provided sufficient documentation to get these implemented, yet...
            //void ActivateDevice();
		    //void DeactivateDevice();
		    
            bool GetDeviceConfigurationData(const TCHAR* pDeviceName, DWORD Space, ULONG BusNumber, ULONG SlotNumber, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const;
		    bool SetDeviceConfigurationData(const TCHAR* pDeviceName, DWORD Space, ULONG BusNumber, ULONG SlotNumber, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const;

		    bool GetDevicePowerState(const TCHAR* pDeviceName, CEDEVICE_POWER_STATE* pState) const;
		    bool SetDevicePowerState(const TCHAR* pDeviceName, CEDEVICE_POWER_STATE* pState) const;
		    
            bool IsChildRemoved(const TCHAR* pDeviceName, bool* pChildState) const;

		    bool TranslateBusAddress(const TCHAR* pDeviceName, INTERFACE_TYPE  InterfaceType, ULONG BusNumber, PHYSICAL_ADDRESS BusAddress, ULONG* pInIoSpace, PHYSICAL_ADDRESS* pTranslatedAddress) const;
		    bool TranslateSystemAddress(const TCHAR* pDeviceName, INTERFACE_TYPE  InterfaceType, ULONG BusNumber, PHYSICAL_ADDRESS BusAddress, PHYSICAL_ADDRESS* pTranslatedAddress) const;

		    bool TransAddrToVirtual(const TCHAR* pDeviceName, INTERFACE_TYPE InterfaceType, ULONG BusNumber, PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const;
		    bool TransAddrToStatic(const TCHAR* pDeviceName, INTERFACE_TYPE InterfaceType, ULONG BusNumber, PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const;
		};

        ///////////////////////////////////////////////////////
        // Description: 
        //    Class to extend BusDriver for use in stream device.
        //
        // Remarks:
        //    This class maintains the stream drivers device name
        //    internally so drivers need not provide that to all
        //    the methods of BusDriver
        //
        // Implementation Notes:
        //    BusDriver is a protected base class to prevent
        //    direct acces to the BusDriver methods without the
        //    correct device name.
        //
        class ParentBusDriver : protected BusDriver
		{
		public:
            ParentBusDriver() {}
            explicit ParentBusDriver(const TCHAR* pRegPath)
            { 
                Open(pRegPath);
            }

            virtual ~ParentBusDriver() { Close(); }

            bool IsValid() const { return BusDriver::IsValid(); }

            bool Open(const TCHAR* pRegPath);

            bool Close();

            bool GetConfigurationData(DWORD Space, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const;
            bool SetConfigurationData(DWORD Space, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const;

            bool GetDevicePowerState(CEDEVICE_POWER_STATE* pState) const;
            bool SetDevicePowerState(CEDEVICE_POWER_STATE* pState) const;
            
            bool IsChildRemoved(bool* pChildState) const;

            bool TranslateBusAddress(PHYSICAL_ADDRESS BusAddress, ULONG* pInIoSpace, PHYSICAL_ADDRESS* pTranslatedAddress) const;
            bool TranslateSystemAddress(PHYSICAL_ADDRESS BusAddress, PHYSICAL_ADDRESS* pTranslatedAddress) const;

            bool TransAddrToVirtual(PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const;
            bool TransAddrToStatic(PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const;
            
            bool GetBusLocation(INTERFACE_TYPE& BusType, UINT32& BusNumber, UINT32& SlotNumber) const;
        
        protected:

            class ParentBusDriverRegValues : public FusionWare::Win32::RegValues
            {
            public:
                ParentBusDriverRegValues(UINT32 DefBusNumber = 0, UINT32 DefSlotNumber = 0) 
                    : BusNumber(DefBusNumber)
                    , SlotNumber(DefSlotNumber)
                {
                }

                INTERFACE_TYPE BusType;
                UINT32 BusNumber;
                UINT32 SlotNumber;

                BEGIN_REG_VALUE_TABLE(ParentBusDriverRegValues)
                    REGVAL_DWORD_REQ(_T("InterfaceType"), BusType)
                    REGVAL_DWORD(_T("BusNumber"), BusNumber)
                    REGVAL_DWORD(_T("SlotNumber"), SlotNumber)
                END_REG_VALUE_TABLE
            };

            ParentBusDriverRegValues BusInfo;
            ce::wstring pDeviceBusName;
		};

        inline bool ParentBusDriver::GetConfigurationData(DWORD Space, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const
        {
            return BusDriver::GetDeviceConfigurationData(this->pDeviceBusName, Space, BusInfo.BusNumber, BusInfo.SlotNumber, Offset, Length, pBuffer, pActualOut);
        }

		inline bool ParentBusDriver::SetConfigurationData(DWORD Space, DWORD Offset, DWORD Length, void* pBuffer, DWORD* pActualOut) const
        {                                                
            return BusDriver::SetDeviceConfigurationData(this->pDeviceBusName, Space, BusInfo.BusNumber, BusInfo.SlotNumber, Offset, Length, pBuffer, pActualOut);
        }

		inline bool ParentBusDriver::GetDevicePowerState(CEDEVICE_POWER_STATE* pState) const
        {
            return BusDriver::GetDevicePowerState(this->pDeviceBusName, pState);
        }

		inline bool ParentBusDriver::SetDevicePowerState(CEDEVICE_POWER_STATE* pState) const
        {
            return BusDriver::SetDevicePowerState(this->pDeviceBusName, pState);
        }
		
        inline bool ParentBusDriver::IsChildRemoved(bool* pChildState) const
        {
            return BusDriver::IsChildRemoved(this->pDeviceBusName, pChildState);
        }

		inline bool ParentBusDriver::TranslateBusAddress(PHYSICAL_ADDRESS BusAddress, ULONG* pInIoSpace, PHYSICAL_ADDRESS* pTranslatedAddress) const
        {
            return BusDriver::TranslateBusAddress(this->pDeviceBusName, BusInfo.BusType, BusInfo.BusNumber, BusAddress, (ULONG*)pInIoSpace, pTranslatedAddress); 
        }

		inline bool ParentBusDriver::TranslateSystemAddress(PHYSICAL_ADDRESS BusAddress, PHYSICAL_ADDRESS* pTranslatedAddress) const
        {
            return BusDriver::TranslateSystemAddress(this->pDeviceBusName, BusInfo.BusType, BusInfo.BusNumber, BusAddress, pTranslatedAddress); 
        }

		inline bool ParentBusDriver::TransAddrToVirtual(PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const
        {
            return BusDriver::TransAddrToVirtual(pDeviceBusName, BusInfo.BusType, BusInfo.BusNumber, BusAddress, Length, (ULONG*)pInIoSpace, ppMappedAddress);
        }

		inline bool ParentBusDriver::TransAddrToStatic(PHYSICAL_ADDRESS BusAddress, ULONG Length, ULONG* pInIoSpace, void** ppMappedAddress) const
        {
            return BusDriver::TransAddrToStatic(this->pDeviceBusName, BusInfo.BusType, BusInfo.BusNumber, BusAddress, Length, (ULONG*)pInIoSpace, ppMappedAddress);
        }
        
        inline bool ParentBusDriver::GetBusLocation(INTERFACE_TYPE& BusType, UINT32& BusNumber, UINT32& SlotNumber) const
        {
            BusType = this->BusInfo.BusType;
            BusNumber = this->BusInfo.BusNumber;
            SlotNumber = this->BusInfo.SlotNumber;
        
            return true;
        }
    }
}